package edu.pku.sei.transformation.editor.model.execution;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;

import edu.pku.sei.gefcommon.descriptor.annotation.EnumerationProperty;
import edu.pku.sei.gefcommon.descriptor.annotation.MethodProperty;
import edu.pku.sei.modeler.model.core.MetaPackage;
import edu.pku.sei.modeler.model.xml.XMLUtility;
import edu.pku.sei.transformation.editor.internal.TransformationEditorModelRoot;
import edu.pku.sei.transformation.editor.model.MetaModel;
import edu.pku.sei.transformation.editor.model.ModelPackage;
import edu.pku.sei.transformation.editor.model.ModelType;
import edu.pku.sei.transformation.editor.model.base.NamedElement;
import edu.pku.sei.transformation.editor.model.constraint.ConstraintConnection;
import edu.pku.sei.transformation.editor.model.constraint.IConstrainableElement;

public class Model extends NamedElement implements IConstrainableElement, INode {
	private ModelType metamodel;
	private ArrayList<ConstraintConnection> constraintConnections = new ArrayList<ConstraintConnection>();
	private ArrayList<ObjectFlow> outgoingObjectFlows = new ArrayList<ObjectFlow>();
	private ArrayList<ObjectFlow> incomingObjectFlows = new ArrayList<ObjectFlow>();
	private String file = "";

	@MethodProperty(catalog = "Model", id = ModelPackage.MODEL_FILE, setter = "setFile", name = "file")
	public String getFile() {
		return file;
	}

	public void setFile(String file) {
		this.file = file;
		firePropertyChange(ModelPackage.MODEL_FILE, null, this.file);
	}

	@MethodProperty(catalog = "Model", id = ModelPackage.MODEL_METAMODEL, setter = "setMetamodel", name = "metamodel")
	@EnumerationProperty(function = "getMetaModels")
	public ModelType getModelType() {
		return metamodel;
	}
	
	public MetaModel getMetaModel() {
		return this.getModelType().getMetaModel();
	}

	public void setMetamodel(ModelType metamodel) {
		ModelType oldValue = this.metamodel;
		this.metamodel = metamodel;
		firePropertyChange(ModelPackage.MODEL_METAMODEL, oldValue,
				this.metamodel);
	}

	public Object[] getMetaModels() {
		MetaPackage modeltypePackage = TransformationEditorModelRoot
				.getModelTypePkg(getModel());
		ArrayList list = new ArrayList();
		if (modeltypePackage != null)
			for (Object object : modeltypePackage.getOtherElements()) {
				if (object instanceof ModelType)
					list.add(object);
			}
		return list.toArray();
	}

	@Override
	public void serialize(Element root) {
		super.serialize(root);
		XMLUtility.xmlInstance.serializeNodeNotContain(root,
				ModelPackage.MODEL_METAMODEL, metamodel);
		XMLUtility.xmlInstance.serializeNodes(root,
				ModelPackage.MODEL_CONSTRAINTS, constraintConnections);
		XMLUtility.xmlInstance.serializeNodes(root,
				ModelPackage.NODE_OUTGOINGS, this.outgoingObjectFlows);
		XMLUtility.xmlInstance.serializeNodesNotContain(root,
				ModelPackage.NODE_INCOMINGS, this.incomingObjectFlows);
		XMLUtility.xmlInstance.serializeAttribute(root,
				ModelPackage.MODEL_FILE, file);
	}

	@Override
	public void deSerialize(Element root) {
		super.deSerialize(root);
		metamodel = (ModelType) XMLUtility.xmlInstance
				.deSerializeNodeNotContain(root, ModelPackage.MODEL_METAMODEL,
						this);
		constraintConnections.addAll(XMLUtility.xmlInstance.deSerializeNodes(
				root, ModelPackage.MODEL_CONSTRAINTS));
		this.outgoingObjectFlows.addAll(XMLUtility.xmlInstance
				.deSerializeNodes(root, ModelPackage.NODE_OUTGOINGS));
		this.incomingObjectFlows.addAll(XMLUtility.xmlInstance
				.deSerializeNodesNotContain(root, ModelPackage.NODE_INCOMINGS,
						this));
		this.file = XMLUtility.xmlInstance.deSerializeString(root,
				ModelPackage.MODEL_FILE);
	}

	@Override
	public void dynamicSet(String featureID, Object value) {
		if (ModelPackage.MODEL_METAMODEL.equals(featureID)) {
			this.metamodel = (ModelType) value;
		} else if (ModelPackage.NODE_INCOMINGS.equals(featureID)) {
			this.incomingObjectFlows.add((ObjectFlow) value);
		} else if (ModelPackage.NODE_OUTGOINGS.equals(featureID)) {
			this.outgoingObjectFlows.add((ObjectFlow) value);
		} else {
			super.dynamicSet(featureID, value);
		}
	}

	@Override
	public String toString() {
		String name = "";
		if (getName() != null)
			name = getName();
		if (getModelType() != null)
			name = name + ":" + getModelType().getName();
		if ("".equals(name)) {
			name = "Model";
		}
		return name;
	}

	@Override
	public List<ConstraintConnection> getConstraintConnections() {
		return this.constraintConnections;
	}

	@Override
	public ArrayList getIncomings() {
		return incomingObjectFlows;
	}

	@Override
	public ArrayList getOutgoings() {
		return outgoingObjectFlows;
	}
}
